package com.habook.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

public class JackMail {

	private Folder folder = null;
	private Store store = null;

	public void close() { // Closing resources no use by now
		try {
			if (folder != null)
				folder.close(true);
			if (store != null)
				store.close();
		} catch (MessagingException e) {
		}
	}

	public Message[] fetchMessages() {
		close();
		Properties prop = new Properties();
		if (Property.INCOMING_PORT != null && !Property.INCOMING_PORT.equals("")) {
			prop.setProperty("mail.pop3.port", Property.INCOMING_PORT);
			prop.setProperty("mail.pop3.socketFactory.port", Property.INCOMING_PORT);
			prop.setProperty("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
			prop.setProperty("mail.pop3.socketFactory.fallback", "false");
		}
		prop.put("mail.pop3.host", Property.MAIL_SERVER_INCOMING);
		prop.put("mail.store.protocol", Property.POP_MAIL);

		Session session = null;
		if (Property.MAIL_SERVER_AUTH != null && Property.MAIL_SERVER_AUTH.equalsIgnoreCase("true")) {
			session = Session.getInstance(prop, new JackAuthenticator());
		} else {
			session = Session.getInstance(prop);
		}

		session.setDebug(Property.MAIL_DEBUG != null ? Property.MAIL_DEBUG.equalsIgnoreCase("true") : false);
		try { // Connect to host
			store = session.getStore(Property.POP_MAIL);
			store.connect(Property.MAIL_SERVER_INCOMING, -1, Property.MAIL_SERVER_USER, Property.MAIL_SERVER_PASSWORD);
		} catch (Exception ex) {
			JOptionPane.showMessageDialog(null, String.format("Connetcion problem: Check %s for 'MAIL_SERVER_HOST', 'MAIL_SERVER_USER', 'MAIL_SERVER_PASSWORD', 'POP_MAIL' and 'SMTP_MAIL' are correct", //
					Property.PROPS_FILE_NAME), "Failed to Connect", JOptionPane.ERROR_MESSAGE);
			return null;
		}

		// Open the default folder
		try {
			folder = store.getDefaultFolder();
		} catch (MessagingException e) {
			return null;
		}
		if (folder == null) {
			JOptionPane.showMessageDialog(null, "There is no default folder in your mail server", "Cant load Mail folder", JOptionPane.ERROR_MESSAGE);
			return null;
		}

		try {
			folder = folder.getFolder(Property.INBOX);
		} catch (MessagingException e) {
			return null;
		}

		if (folder == null) {
			JOptionPane.showMessageDialog(null, "No default folder to view from your mail Client", "Cant load Mail folder", JOptionPane.ERROR_MESSAGE);
			return null;
		}

		// Get message count
		try {
			folder.open(Folder.READ_WRITE);
		} catch (MessagingException e) {
			return null;
		}
		int totalMessages;
		try {
			totalMessages = folder.getMessageCount();
		} catch (MessagingException e) {
			return null;
		}
		System.out.println("TotalMessages = " + totalMessages);

		// Get attributes & flags for all messages
		try {
			return folder.getMessages();
		} catch (MessagingException e) {
			return null;
		} 
	}

	public String readMessage(Message message) {
		try {
			StringBuffer buffer = new StringBuffer();

			if (message != null) {
				buffer.append("Subject: " + message.getSubject() + "\n");

				/*
				 * THIS CALL USED TO WRITE THE ATTACHMENT TO YOUR HARD DISK.
				 */
				boolean contentFlag = false;//doJack(message);

				if (!contentFlag) {
					BufferedReader is = new BufferedReader(new InputStreamReader(message.getInputStream()));
					String line = "";
					boolean flag = false;
					int counter = 0;
					while ((line = is.readLine()) != null) {
						if (line.startsWith("Content-Transfer-")) {
							flag = true;
							counter++;
						}
						if (flag == true && line.indexOf("_NextPart_") > 0) {
							flag = false;
							counter++;
						}
						if (counter == 1 && !line.startsWith("Content-Transfer-")) {
							buffer.append(line + "\n");
						}
					}
				} else {
					buffer.append("" + message.getContent());
				}
			}

			return buffer.toString();
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, "IO exception: " + e.getMessage().substring(0, 20), "Unable to read message this time", JOptionPane.ERROR_MESSAGE);
			return "";
		}
	}

	/**
	 * Be fore loading message in table, it checks whether any mail has any
	 * attachment or not
	 * 
	 * @param m
	 *            Message
	 * @return true
	 * @deprecated very heavy to use, before it was used in was used in
	 *             CreateData() in MailListPanel
	 */
	public boolean hasAttachment(Message m) {
		boolean flag = false;
		try {
			if (m.getContent() instanceof Multipart) {
				Multipart multipart = (Multipart) m.getContent();
				for (int z = 0; z < multipart.getCount(); z++) {
					BodyPart part = multipart.getBodyPart(z);
					String disposition = part.getDisposition();
					if ((disposition != null) && (disposition.equals(Part.ATTACHMENT) || (disposition.equals(Part.INLINE)))) {
						/*
						 * Here there is an attachment
						 */
						flag = true;
						break;
					}
				}
			}
		} catch (Exception ex) {
			// Do nothing
			flag = false;
		}
		return flag;
	}

	/**
	 * The doJack.
	 * 
	 * @param m
	 *            Message
	 * @return boolean
	 */
	private boolean doJack(Message m) {
		String filepath = "";
		Multipart multipart;
		try {
			if (m.getContent() instanceof Multipart) {
				multipart = (Multipart) m.getContent();
				for (int z = 0; z < multipart.getCount(); z++) {
					BodyPart part = multipart.getBodyPart(z);
					String disposition = part.getDisposition();
					if ((disposition != null) && (disposition.equals(Part.ATTACHMENT) || (disposition.equals(Part.INLINE)))) {
						/*
						 * Here allowing user to choose to save or left out
						 */
						int reply = JOptionPane.showConfirmDialog(null, "Do you like to save [" + part.getFileName() + "] sent with this mail", "Jack Attachment Saver", JOptionPane.YES_NO_OPTION);
						if (reply == JOptionPane.YES_OPTION) {
							// Here goes to allow user to specify location

							JFileChooser chooser = new JFileChooser();
							chooser.setCurrentDirectory(new java.io.File(System.getProperty("user.home")));
							chooser.setDialogTitle("Select The Folder where you want to save");
							chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
							chooser.setSelectedFile(new File(part.getFileName()));
							//
							// disable the "All files" option.
							//
							chooser.setAcceptAllFileFilterUsed(false);
							//    
							if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
								filepath = chooser.getSelectedFile().toString();
								String filename = filepath + "/" + part.getFileName();
								File file = new File(filename);
								file.createNewFile();
								InputStream in = part.getInputStream();
								FileOutputStream fos = new FileOutputStream(file);
								byte[] buf = new byte[1024];
								int c = 0;
								while ((c = in.read(buf)) != -1) {
									fos.write(buf, 0, c);
								}
								in.close();
								fos.close();
							}
						} else {
						}
					} else {
						continue;
					}
				}
			} else if (m.getContent() instanceof String) {
				return true;
			}
		} catch (IOException exception) {
			JOptionPane.showMessageDialog(null, "IO exception:" + exception.getMessage().substring(0, 20), "Unable to save attachemtnt", JOptionPane.ERROR_MESSAGE);
		} catch (MessagingException exception) {
			JOptionPane.showMessageDialog(null, "Message exception:" + exception.getMessage().substring(0, 20), "Unable to save attachemtnt", JOptionPane.ERROR_MESSAGE);
		}
		return false;
	}

	public boolean sendMailWithAtt(String sender_name, String email_from, String email_to, String email_cc, String email_bcc, String email_subject, String email_body, File file_name) {
		boolean result = true;
		try {
			// Gets the System properties
			Properties props = new Properties();
			props.setProperty("mail.transport.protocol", "smtp");
			props.setProperty("mail.host", Property.MAIL_SERVER_OUTGOING);
			if (Property.MAIL_SERVER_AUTH != null && Property.MAIL_SERVER_AUTH.equalsIgnoreCase("true")) {
				props.put("mail.smtp.auth", Property.MAIL_SERVER_AUTH);
			}
			if (Property.OUTGOING_PORT != null && !Property.OUTGOING_PORT.trim().equals("")) {
				props.put("mail.smtp.port", Property.OUTGOING_PORT);
				props.put("mail.smtp.socketFactory.port", Property.OUTGOING_PORT);
				props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
				props.put("mail.smtp.socketFactory.fallback", "false");
				props.setProperty("mail.smtp.quitwait", "false");
			}

			Session session = null;
			if (Property.MAIL_SERVER_AUTH != null && Property.MAIL_SERVER_AUTH.equalsIgnoreCase("true")) {
				session = Session.getInstance(props, new JackAuthenticator());
			} else {
				session = Session.getInstance(props);
			}
			// Get the default Session using Properties Object
			// Session session = Session.getDefaultInstance(l_props, null);

			session.setDebug(Property.MAIL_DEBUG != null ? Property.MAIL_DEBUG.equalsIgnoreCase("true") : false); // Enable
			// the
			// debug
			// mode

			// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
			// Define message
			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress(email_from));
			/*
			 * Multiple receipent to
			 */

			if (email_to != null && !email_to.trim().equals("")) {
				String tos[] = email_to.trim().split(",");
				Address toAdd[] = new Address[tos.length];
				for (int i = 0; i < toAdd.length; i++) {
					toAdd[i] = new InternetAddress(tos[i]);
				}
				message.addRecipients(Message.RecipientType.TO, toAdd);
			}

			/*
			 * Multiple receipent cc
			 */

			if (email_cc != null && !email_cc.trim().trim().equals("")) {
				String ccs[] = email_cc.split(",");
				Address ccAdd[] = new Address[ccs.length];
				for (int i = 0; i < ccAdd.length; i++) {
					ccAdd[i] = new InternetAddress(ccs[i]);
				}
				message.addRecipients(Message.RecipientType.CC, ccAdd);
			}

			/*
			 * Multiple receipent bcc
			 */

			if (email_bcc != null && !email_bcc.trim().trim().equals("")) {
				String bccs[] = email_bcc.split(",");
				Address bccAdd[] = new Address[bccs.length];
				for (int i = 0; i < bccAdd.length; i++) {
					bccAdd[i] = new InternetAddress(bccs[i]);
				}
				message.addRecipients(Message.RecipientType.BCC, bccAdd);
			}

			message.setSubject(email_subject);
			message.setSentDate(new Date());
			/*
			 * Body created
			 */
			BodyPart messageBodyPart = new MimeBodyPart();

			/*
			 * pushing the bosy text
			 */
			messageBodyPart.setText(email_body);

			Multipart multipart = new MimeMultipart();
			multipart.addBodyPart(messageBodyPart);

			/*
			 * If any attachement
			 */
			messageBodyPart = new MimeBodyPart();
			if (file_name != null) {
				DataSource source = new FileDataSource(file_name);
				messageBodyPart.setDataHandler(new DataHandler(source));
				messageBodyPart.setFileName(file_name.getName());
				multipart.addBodyPart(messageBodyPart);
			}

			/*
			 * allowing support for attachment
			 */
			message.setContent(multipart);

			/*
			 * Boom!
			 */
			Transport.send(message);

			// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
		} catch (MessagingException mex) { // Trap the MessagingException Error
			result = false;
		}
		return result;
	}

	private class JackAuthenticator extends javax.mail.Authenticator {
		public PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication(Property.MAIL_SERVER_USER, Property.MAIL_SERVER_PASSWORD);
		}
	}

	public static boolean syncMail(String text) {
		JackMail jackmail = new JackMail();
		try { // Note Version Control and set LastSyncNote if Success
			// get last version note
			// merge note
			// send note
			// set local note
			Property.setLastSyscNote(text);
			return true;
		} catch (Exception e) {
			return false;
		} finally {
			jackmail.close();
		}
	}
	
	public static void main(String[] args) {
		JackMail jackmail = new JackMail();
		Message[] msgs = jackmail.fetchMessages();
		System.out.println("ok");
		for (int i = 0; i < msgs.length; i++) {
			System.out.println(jackmail.readMessage(msgs[i]));
		}
	}
}
